import java.net.*;
import java.io.*;
import java.util.*;

/**
CGIStuff is a class that holds methods useful to anyone writing a CGI back-end in Java.
It's supplied as part of the JavaCGI package.
@author Ben Last (ben@hypereality.co.uk)
@version 1.0, 4/7/96
*/

public class CGI
{
   //full of class methods, really.

   /**
      Split a QUERY_STRING (or the contents of stdin for a POST) into a HashTable.
      The method doesn't expect <VAR>queryString</VAR> to have been urlDecoded.  It will
      decode all the variables and names.
   */
   public static Hashtable splitVars(String queryString)
   {
      return splitCodedVars(queryString, true);
   }
   
   protected static Hashtable splitCodedVars(String queryString, boolean decode)
   {
   Hashtable   vars = new Hashtable();
   String      name = null;
   boolean     asName = true;
   
      //We mustn't decode the string yet because that might introduce more '&' characters
      //which we don't want.

      //split at every '&' or '=' into substrings.  We need also to handle the
      //fact that the final variable doesn't end in an '&'.
      StringTokenizer st = new StringTokenizer(queryString, "&=", true);
      while(st.hasMoreTokens())
      {
         String var = st.nextToken();
         //if we've been returned an '=' or an '&', that tells us
         //what the next token should be treated as.
         if(var.equals("="))
         {
            asName = false;   //next token is a value
            continue;
         }

         if(var.equals("&"))
         {
            //we may have a name, but no value, in which case we add it as an
            //empty property.
            if(name != null)
            {
               vars.put(name,"");
               name = null;
            }
            asName = true; //next token is a name
            continue;
         }

         if(asName)
         {
            name = decode ? URLDecoder.decode(var) : var;
            continue;
         }

         //we have a value.  If we also have a name, then add as a property.
         if(name != null)
         {
            vars.put(name, decode ? URLDecoder.decode(var) : var);
            name = null;
         }
      }

      //if name is not null here, we had a trailing empty valueless variable.
      if(name != null)
         vars.put(name,"");

      return vars;
   }
   
   public static String joinHashtableVars(Hashtable vars) {
      boolean first = true;
      String key, value;
      String ret = "";
                  
      for (Enumeration keys = vars.keys(); keys.hasMoreElements(); first = false) {
         key = (String) keys.nextElement();

         if (!first) {
            ret += "&";
         }
         ret += URLEncoder.encode(key) + "=" + URLEncoder.encode((String) vars.get(key));
      }
      
      return ret;
   }
 
   public static String post(URL url, Hashtable headers, Hashtable data) throws IOException {
      String content, line, response, key;    
      HttpURLConnection connection;
      DataInputStream in;
      DataOutputStream out;
      int responseCode;
            
      // Create the URL and its connection
      connection = (HttpURLConnection) url.openConnection();
      
      // Setup our connection state    
      connection.setRequestMethod("POST");
      connection.setDoInput(true);
      connection.setDoOutput(true);    
      connection.setUseCaches(false);
    
      // Build the content string from the hashtable
      content = CGI.joinHashtableVars(data);
         
      // We want to do a post operation
      connection.setRequestProperty("Content-type", "application/x-www-form-urlencoded");
      connection.setRequestProperty("Content-length", new Integer(content.length()).toString());

      for (Enumeration keys = headers.keys(); keys.hasMoreElements(); ) {
         key = (String) keys.nextElement();
         connection.setRequestProperty(key, (String) headers.get(key));
      }
     
      // Get an input and output stream for sending/receiving data
      out = new DataOutputStream(connection.getOutputStream());

      System.out.print("Sending message...");
      // Send the data and close the output stream
      out.writeBytes(content);
      out.flush();
      out.close();      
      System.out.println("done.");             
 
      // Read the server response    
      response = "";
      responseCode = connection.getResponseCode();
      if (responseCode != 200) {
         IOException e = new IOException("Server Error: " + responseCode + " " + connection.getResponseMessage());
         throw(e);
      }         
      in = new DataInputStream(connection.getInputStream()); 
      while ((line = in.readLine()) != null) {
         response += line + "\n";
      }    
 
      in.close();
      System.out.println("Message sent.");
      
      return response;
   }
        
}
